package myLearnjdk.jdk.lang;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ClassLoaderTest {
	public static void main(String[] args) {
		
	}
	
	
	/**
	 * 文件类加载器
	 */
	public static void testFileClassloader(){
		FileSystemClassLoader f  =  new FileSystemClassLoader("");
		
	}

}
/**
 * 自定义文件系统类加载器(根据类的全类名 到指定目录下加载对应.class文件)
 * @author yangcheng  
 * @date 2018年5月5日
 */
class FileSystemClassLoader extends ClassLoader{
	String dirRoot = null;
	public FileSystemClassLoader(String dirRoot) {
		this.dirRoot = dirRoot;
	}
	/**
	 * 重写加载类的方法
	 * name是类的全类名
	 */
	@Override
	public Class<?> loadClass(String name) throws ClassNotFoundException {
		//直接调用查看是否已经加载指定的类
		Class<?> clazz = findLoadedClass(name);
		if(clazz != null ){
			//如果已经加载 则直接返回
			return clazz;
		}else{
			//否则通过父类加载对应的类(双亲委派模式)
			try{
				clazz = super.loadClass(name);
			}catch(Exception e){
				//自定义加载器的父类是"应用程序类加载器"，jvm默认的就是这个类加载器，由于其在
				//未加载到指定类的时候会报异常，会影响到自定义类加载器的机制，因此，我们需要捕获他。
			}
			
			if(clazz != null){
				return clazz;
			}else{
				//如果父类也没有加载到相应的类 则 自己加载
				//1.获取类文件的字节数组
				byte[] bytes = getBytesByName(name);
				//2.调用difineClass()方法 加载字节数组对应的Class类
				clazz = defineClass(name, bytes, 0, bytes.length);
				if(clazz == null){
					throw new ClassNotFoundException();
				}else{
					return clazz;
				}
			}
		}
		
	}
	
	
	
	public byte[] getBytesByName(String name){
		String path = dirRoot+"/"+name.replace(".", "/")+".class";
		
		InputStream is = null;
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		try{
			is  = new FileInputStream(path);
			
			byte[] buffer = new byte[1024];
			int temp=0;
			while((temp=is.read(buffer))!=-1){
				baos.write(buffer, 0, temp);
			}
			
			return baos.toByteArray();
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}finally{
			try {
				if(is!=null){
					is.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if(baos!=null){
					baos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}	
	}

}
